package org.cybzacg.convert.converters.gather;

import org.cybzacg.convert.annotation.Converter;
import org.cybzacg.convert.context.ConversionContext;
import org.cybzacg.convert.core.AbstractTypeConverter;
import org.cybzacg.convert.enums.ConversionError;
import org.cybzacg.convert.enums.ConversionPriority;
import org.cybzacg.convert.enums.ConversionType;
import org.cybzacg.convert.exception.ConversionException;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;

/**
 * 数组类型转换器
 * 支持各种数组类型之间的转换
 *
 * @author cybzacg.blog
 * @version 4.0
 * @since 3.0
 */
@Slf4j
@Converter(name = "ArrayConverter", priority = ConversionPriority.MEDIUM, description = "数组类型转换器，支持各种数组类型之间的转换", enabled = true, version = "4.0", author = "cybzacg.blog", supportedTypes = {
        Object[].class }, tags = { "array", "collection", "conversion" })
public class ArrayConverter extends AbstractTypeConverter {

    public ArrayConverter() {
        super(ConversionPriority.MEDIUM);
        log.debug("ArrayConverter 初始化完成");
    }

    @Override
    protected ConversionType getConversionType() {
        return ConversionType.ARRAY;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected <T> T doConvert(Object source, Class<T> targetType, T defaultValue, ConversionContext context)
            throws Exception {

        if (source == null) {
            return defaultValue;
        }

        // 如果已经是目标类型，直接返回
        if (targetType.isInstance(source)) {
            return (T) source;
        }

        // 转换为数组
        return (T) convertToArray(source, targetType, context);
    }

    /**
     * 将对象转换为目标类型的数组
     */
    protected Object convertToArray(Object source, Class<?> targetType, ConversionContext context)
            throws ConversionException {

        if (source == null) {
            return createEmptyArray(targetType);
        }

        // 数组转数组
        if (source.getClass().isArray()) {
            return convertArrayToArray(source, targetType, context);
        }

        // 集合转数组
        if (source instanceof Collection) {
            return convertCollectionToArray((Collection<?>) source, targetType, context);
        }

        // Map转数组
        if (source instanceof Map) {
            return convertMapToArray((Map<?, ?>) source, targetType, context);
        }

        // 字符串转数组
        if (source instanceof String) {
            return convertStringToArray((String) source, targetType, context);
        }

        // 单个对象转数组
        return convertObjectToArray(source, targetType, context);
    }

    /**
     * 数组转数组
     */
    protected Object convertArrayToArray(Object source, Class<?> targetType, ConversionContext context)
            throws ConversionException {

        // 获取源数组信息
        Class<?> sourceComponentType = source.getClass().getComponentType();
        int sourceLength = Array.getLength(source);

        // 获取目标数组信息
        Class<?> targetComponentType = targetType.getComponentType();
        if (targetComponentType == null) {
            throw new ConversionException(ConversionError.UNSUPPORTED_CONVERSION,
                    "目标类型不是数组类型: " + targetType.getSimpleName());
        }

        // 创建目标数组
        Object targetArray = Array.newInstance(targetComponentType, sourceLength);

        // 复制元素
        for (int i = 0; i < sourceLength; i++) {
            Object element = Array.get(source, i);
            Object convertedElement = convertArrayElement(element, targetComponentType, context);
            Array.set(targetArray, i, convertedElement);
        }

        return targetArray;
    }

    /**
     * 集合转数组
     */
    protected Object convertCollectionToArray(Collection<?> source, Class<?> targetType, ConversionContext context)
            throws ConversionException {

        Class<?> targetComponentType = targetType.getComponentType();
        if (targetComponentType == null) {
            throw new ConversionException(ConversionError.UNSUPPORTED_CONVERSION,
                    "目标类型不是数组类型: " + targetType.getSimpleName());
        }

        // 创建目标数组
        Object targetArray = Array.newInstance(targetComponentType, source.size());

        // 转换元素
        int index = 0;
        for (Object element : source) {
            Object convertedElement = convertArrayElement(element, targetComponentType, context);
            Array.set(targetArray, index++, convertedElement);
        }

        return targetArray;
    }

    /**
     * Map转数组
     */
    protected Object convertMapToArray(Map<?, ?> source, Class<?> targetType, ConversionContext context)
            throws ConversionException {

        Class<?> targetComponentType = targetType.getComponentType();
        if (targetComponentType == null) {
            throw new ConversionException(ConversionError.UNSUPPORTED_CONVERSION,
                    "目标类型不是数组类型: " + targetType.getSimpleName());
        }

        // 根据上下文属性决定转换方式
        String mapConversionMode = context.getProperty("mapConversionMode");
        if (mapConversionMode == null) {
            mapConversionMode = "entries";
        }

        Collection<?> elements = switch (mapConversionMode.toLowerCase()) {
            case "keys" -> source.keySet();
            case "values" -> source.values();
            default -> source.entrySet();
        };

        // 创建目标数组
        Object targetArray = Array.newInstance(targetComponentType, elements.size());

        // 转换元素
        int index = 0;
        for (Object element : elements) {
            Object convertedElement = convertArrayElement(element, targetComponentType, context);
            Array.set(targetArray, index++, convertedElement);
        }

        return targetArray;
    }

    /**
     * 字符串转数组
     */
    protected Object convertStringToArray(String source, Class<?> targetType, ConversionContext context)
            throws ConversionException {

        if (source == null || source.trim().isEmpty()) {
            return createEmptyArray(targetType);
        }

        Class<?> targetComponentType = targetType.getComponentType();
        if (targetComponentType == null) {
            throw new ConversionException(ConversionError.UNSUPPORTED_CONVERSION,
                    "目标类型不是数组类型: " + targetType.getSimpleName());
        }

        // 获取分隔符
        String separator = context.getProperty("arraySeparator");
        if (separator == null) {
            separator = ",";
        }

        // 分割字符串
        String[] parts = source.split(separator.trim());

        // 创建目标数组
        Object targetArray = Array.newInstance(targetComponentType, parts.length);

        // 转换元素
        for (int i = 0; i < parts.length; i++) {
            String part = parts[i].trim();
            Object convertedElement = convertArrayElement(part, targetComponentType, context);
            Array.set(targetArray, i, convertedElement);
        }

        return targetArray;
    }

    /**
     * 单个对象转数组
     */
    protected Object convertObjectToArray(Object source, Class<?> targetType, ConversionContext context)
            throws ConversionException {

        Class<?> targetComponentType = targetType.getComponentType();
        if (targetComponentType == null) {
            throw new ConversionException(ConversionError.UNSUPPORTED_CONVERSION,
                    "目标类型不是数组类型: " + targetType.getSimpleName());
        }

        // 创建包含一个元素的数组
        Object targetArray = Array.newInstance(targetComponentType, 1);
        Object convertedElement = convertArrayElement(source, targetComponentType, context);
        Array.set(targetArray, 0, convertedElement);

        return targetArray;
    }

    /**
     * 转换数组元素
     */
    protected Object convertArrayElement(Object element, Class<?> targetComponentType, ConversionContext context)
            throws ConversionException {

        if (element == null) {
            return getDefaultValueForType(targetComponentType);
        }

        // 如果元素已经是目标类型，直接返回
        if (targetComponentType.isInstance(element)) {
            return element;
        }

        // 基本类型转换
        if (targetComponentType.isPrimitive()) {
            return convertToPrimitive(element, targetComponentType);
        }

        // 字符串转换
        if (targetComponentType == String.class) {
            return element.toString();
        }

        // 数字类型转换
        if (Number.class.isAssignableFrom(targetComponentType)) {
            return convertToNumber(element, targetComponentType);
        }

        // 布尔类型转换
        if (targetComponentType == Boolean.class || targetComponentType == boolean.class) {
            return convertToBoolean(element);
        }

        // 默认返回原对象
        return element;
    }

    /**
     * 转换为基本类型
     */
    protected Object convertToPrimitive(Object value, Class<?> primitiveType) throws ConversionException {
        try {
            if (value instanceof Number number) {
                if (primitiveType == int.class)
                    return number.intValue();
                if (primitiveType == long.class)
                    return number.longValue();
                if (primitiveType == double.class)
                    return number.doubleValue();
                if (primitiveType == float.class)
                    return number.floatValue();
                if (primitiveType == short.class)
                    return number.shortValue();
                if (primitiveType == byte.class)
                    return number.byteValue();
                if (primitiveType == char.class)
                    return (char) number.intValue();
            }

            if (value instanceof String) {
                String str = (String) value;
                if (primitiveType == int.class)
                    return Integer.parseInt(str);
                if (primitiveType == long.class)
                    return Long.parseLong(str);
                if (primitiveType == double.class)
                    return Double.parseDouble(str);
                if (primitiveType == float.class)
                    return Float.parseFloat(str);
                if (primitiveType == short.class)
                    return Short.parseShort(str);
                if (primitiveType == byte.class)
                    return Byte.parseByte(str);
                if (primitiveType == char.class)
                    return str.charAt(0);
            }

            if (primitiveType == boolean.class) {
                return convertToBoolean(value);
            }

        } catch (Exception e) {
            throw new ConversionException(ConversionError.CONVERSION_FAILED,
                    "无法转换为基本类型: " + value + " -> " + primitiveType, e);
        }

        throw new ConversionException(ConversionError.UNSUPPORTED_CONVERSION,
                "不支持的类型转换: " + value + " -> " + primitiveType);
    }

    /**
     * 转换为数字
     */
    protected Object convertToNumber(Object value, Class<?> numberType) throws ConversionException {
        try {
            if (value instanceof Number number) {
                if (numberType == Integer.class)
                    return number.intValue();
                if (numberType == Long.class)
                    return number.longValue();
                if (numberType == Double.class)
                    return number.doubleValue();
                if (numberType == Float.class)
                    return number.floatValue();
                if (numberType == Short.class)
                    return number.shortValue();
                if (numberType == Byte.class)
                    return number.byteValue();
            }

            if (value instanceof String) {
                String str = (String) value;
                if (numberType == Integer.class)
                    return Integer.parseInt(str);
                if (numberType == Long.class)
                    return Long.parseLong(str);
                if (numberType == Double.class)
                    return Double.parseDouble(str);
                if (numberType == Float.class)
                    return Float.parseFloat(str);
                if (numberType == Short.class)
                    return Short.parseShort(str);
                if (numberType == Byte.class)
                    return Byte.parseByte(str);
            }

        } catch (Exception e) {
            throw new ConversionException(ConversionError.CONVERSION_FAILED,
                    "无法转换为数字: " + value + " -> " + numberType, e);
        }

        throw new ConversionException(ConversionError.UNSUPPORTED_CONVERSION,
                "不支持的数字转换: " + value + " -> " + numberType);
    }

    /**
     * 转换为布尔值
     */
    protected Object convertToBoolean(Object value) throws ConversionException {
        if (value instanceof Boolean) {
            return value;
        }

        if (value instanceof String) {
            String str = ((String) value).toLowerCase().trim();
            return "true".equals(str) || "1".equals(str) || "yes".equals(str) || "on".equals(str);
        }

        if (value instanceof Number number) {
            return number.intValue() != 0;
        }

        return value != null;
    }

    /**
     * 创建空数组
     */
    protected Object createEmptyArray(Class<?> targetType) throws ConversionException {
        Class<?> componentType = targetType.getComponentType();
        if (componentType == null) {
            throw new ConversionException(ConversionError.UNSUPPORTED_CONVERSION,
                    "目标类型不是数组类型: " + targetType.getSimpleName());
        }

        return Array.newInstance(componentType, 0);
    }

    /**
     * 获取类型的默认值
     */
    protected Object getDefaultValueForType(Class<?> type) {
        if (type == boolean.class)
            return false;
        if (type == char.class)
            return '\0';
        if (type == byte.class)
            return (byte) 0;
        if (type == short.class)
            return (short) 0;
        if (type == int.class)
            return 0;
        if (type == long.class)
            return 0L;
        if (type == float.class)
            return 0.0f;
        if (type == double.class)
            return 0.0d;
        return null;
    }

    @Override
    public boolean supports(Class<?> targetType) {
        return getSupportedType().isAssignableFrom(targetType);
    }

    @Override
    public Class<?> getSupportedType() {
        return Object[].class;
    }

    /**
     * 检查是否为数组类型
     *
     * @param clazz 类型
     * @return 是否为数组类型
     */
    public static boolean isArrayType(Class<?> clazz) {
        return clazz != null && clazz.isArray();
    }

    /**
     * 获取数组的组件类型
     *
     * @param arrayClass 数组类型
     * @return 组件类型
     */
    public static Class<?> getComponentType(Class<?> arrayClass) {
        return arrayClass != null ? arrayClass.getComponentType() : null;
    }

    /**
     * 获取数组长度
     *
     * @param array 数组对象
     * @return 数组长度
     */
    public static int getArrayLength(Object array) {
        return array != null && array.getClass().isArray() ? Array.getLength(array) : 0;
    }

    /**
     * 安全的数组转换
     *
     * @param <T>        目标类型
     * @param source     源对象
     * @param targetType 目标类型
     * @return 转换结果
     */
    @SuppressWarnings("unchecked")
    public static <T> T convertSafely(Object source, Class<T> targetType) {
        if (source == null) {
            return null;
        }

        if (targetType.isInstance(source)) {
            return (T) source;
        }

        ArrayConverter converter = new ArrayConverter();
        try {
            return (T) converter.convertToArray(source, targetType, null);
        } catch (Exception e) {
            throw new ConversionException(ConversionError.CONVERSION_FAILED,
                    "安全数组转换失败: " + source + " -> " + targetType, e);
        }
    }
}
